#ifndef ANALYZER_COMMON
#define ANALYZER_COMMON

#ifndef CALCULATE_TYPE_R64
#define CALCULATE_TYPE_R64
#endif

#if defined(CALCULATE_TYPE_R64)
typedef double sparse_value_t;
#elif defined(CALCULATE_TYPE_CR64)
typedef double _Complex sparse_value_t;
typedef double sparse_value_real_t;
#define COMPLEX_MTX
#else
#error[Compile Error] Unknown value type. Set -DCALCULATE_TYPE_CR64 or -DCALCULATE_TYPE_R64 in compile command line.
#endif


typedef long long int analyzer_int64_t;
typedef unsigned long long int analyzer_uint64_t;
typedef int analyzer_int32_t;
typedef unsigned int analyzer_uint32_t;
typedef short int analyzer_int16_t;
typedef unsigned short int analyzer_uint16_t;
typedef analyzer_uint64_t analyzer_exblock_ptr;
typedef analyzer_uint32_t analyzer_exblock_idx;
typedef analyzer_uint32_t analyzer_inblock_ptr;
typedef analyzer_uint16_t analyzer_inblock_idx;

typedef analyzer_exblock_ptr sparse_pointer_t;
#define FMT_SPARSE_POINTER_T "%llu"
typedef analyzer_uint32_t sparse_index_t;
#define FMT_SPARSE_INDEX_T "%u"

#include <unistd.h>
#define __USE_GNU
#include <sched.h>
#include <pthread.h>
#include <omp.h>
#include <sys/resource.h>
#include <getopt.h>
#include <stdio.h>
#include <math.h>
#include "mmio_common.h"
#define MIN(a, b) (((a) < (b))?(a):(b))
#define MAX(a, b) (((a) > (b))?(a):(b))
#define ICEIL(a, b) (((a) + (b) - 1) / (b))
#define setbit(x, y) x |= (1 << y)    // set the yth bit of x is 1
#define getbit(x, y) ((x) >> (y) & 1) // get the yth bit of x

typedef struct
{
    char *name;
    sparse_index_t m;
    sparse_index_t n;
    sparse_index_t is_sym;
    sparse_pointer_t nnz;
    sparse_pointer_t *rowpointer;
    sparse_index_t *columnindex;
    sparse_value_t *value;
} sparse_matrix_t;

extern char buf[500];

sparse_matrix_t *init_smatrix();
int read_matrix(char *mtx_name, sparse_matrix_t *smatrix);
int export_lid(const char *path, sparse_matrix_t *smatrix);
int export_mtx(const char *path, sparse_matrix_t *smatrix);
int get_triangle(int upper, int onlystruct, sparse_matrix_t *src, sparse_matrix_t *dst);
int matrix_analyze(sparse_matrix_t* s);
void exclusive_scan_sparse_pointer(sparse_pointer_t *input, int length);
int findlevel(
    const sparse_pointer_t *cscColPtr,
    const sparse_index_t *cscRowIdx,
    const sparse_pointer_t *csrRowPtr,
    const sparse_index_t m,
    int *nlevel,
    int *levelPtr,
    int *levelItem
);
void matrix_transposition(
    const sparse_index_t m,
    const sparse_index_t n,
    const sparse_pointer_t nnz,
    const sparse_pointer_t *csrRowPtr,
    const sparse_index_t *csrColIdx,
    const sparse_value_t *csrVal,
    sparse_index_t *cscRowIdx,
    sparse_pointer_t *cscColPtr,
    sparse_value_t *cscVal
);
int findlevel_csr(
    const sparse_pointer_t *csrRowPtr,
    const sparse_index_t *csrColIdx,
    const sparse_value_t *csrVal,
    const sparse_index_t m,
    const sparse_index_t n,
    const sparse_pointer_t nnz,
    int *nlevel,
    int *parallelism_min,
    int *parallelism_avg,
    int *parallelism_max
);
int level_set_detect(sparse_matrix_t* s);

void analyzer_timer_start(struct timeval* start);

double analyzer_timer_stop(struct timeval* start);

void dblas_3x3_gemm_a_eq_axb(register double* ap0, register double* bp0);

void dblas_3x3_gemm_b_eq_axb(register double* ap0, register double* bp0);

void dblas_3x3_gemm_c_minus_axb(register double* a, register double* b, register double* c);
// void dblas_3x3_gemm_c_minus_axb(volatile register double *a, volatile register double *b, volatile register double *c);

void dblas_3x3_inv(register double* a);

int analyzer_structed_sparse(sparse_matrix_t* s, int block_order);



#endif